package com.dev;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
import com.log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
public class CIndentEditor extends BaseIndentEditor{
	final static String s1="c_source_text_size";
	final static String s2="c_editor_bgcolor";
	static Paint selectionbgcolor=new Paint();
	static int stringColor=0xffff0000;
	static int commentColor=0xff007f00;
	static int operator=0xff0000ff;
	static int baseType=0xffff00ff;
	static int keywordColor=0xff007fff;
	static char[] operators;
	StringBuilder text;
	//short[] textws;
	int handledl;
	int baseline;
	int primex;
	int primey;
	int lineNumberStart;
	int lineNumberColor=0x88999999;
    int intEnum;
	volatile boolean handleOnShow;
	ArrayList<TabSpan> tabs=new ArrayList<TabSpan>(1024);
	MyInputConnection mic;
	Paint cursor=new Paint();
	Paint lineNumber=new Paint();
	Paint selection=new Paint();
	CEditorPage cep;
	public class TabSpan{
		int tab=0;
		int start;
		int end;
		int width;
		int textColor=CIndentEditor.this.textColor;
		String string;
		float[] fs;
		TabSpan next;
		TabSpan(int start){
			this.start=start;
		}
	}
    public CIndentEditor(CEditorPage cep){
		super(cep.ma);
		this.cep=cep;
		selectionbgcolor.setColor(super.selectionbgcolor);
		setPadding((int)(6*ma.dp),8,0,0);
		textPaint.setTypeface(Typeface.MONOSPACE);
		letTextSize((int)ma.dp*ma.shr.getInt(s1,15));
		handledl=(int)(12*ma.dp);
		selection.setColor(lineNumberColor);
		inertia=0.002f;
		minSpeed=0.001f;
		lineHighlight.setColor(currentLineHighlight);
		if(words_hashSet.isEmpty()){
			for(int index=0;index<words.length;index++){
				words_hashSet.add(words[index]);
			}
		}
		if(operators==null){
			operators=new char[]{
				'<','=','>','&','|','{','}','*',',','.',
				'+','-','(',')',';','[',']'
			};
			Arrays.sort(operators);
		}
	}
    void atTextChanged(){
        invalidate();
        GUI gui=ma.gui;
        if(gui.tfNow instanceof CEditorTab){
            CEditorTab cet=(CEditorTab)gui.tfNow;
            //CEditorPage cep=cet.cep;
            cet.canSave=true;
            gui.ivSave.setColorFilter(null);
            gui.ivSave.invalidate();
            gui.ivRefresh.setColorFilter(null);
            gui.ivRefresh.invalidate();
        }
    }
	@Override
	public int length() {
		return text.length();
	}
	public void letText(StringBuilder sb){
		text=sb;
		int len=sb.length();
		//if(textws==null||textws.length<len)textws=new short[len];
		TabSpan ts=new TabSpan(0);
		tabs.clear();
		tabs.add(ts);
		//int enumBefore=0;
		outmost:
		for(int index=0;index<len;index++){
			char ch=sb.charAt(index);
			if(ch=='\n'){//outmost
				ts.end=index;
				String sub=sb.substring(ts.start,index+1);
				ts.string=sub;
				ts.width=(int)textPaint.measureText(sub);
				ts=new TabSpan(index+1);
				tabs.add(ts);
			}else if(ch=='\t'){//outmost
				ts.tab++;
				int indexSaved=index;
				for(index++;index<len;index++){
					ch=sb.charAt(index);
					if(ch=='\n'){
						String sub=sb.substring(ts.start,indexSaved);
						ts.end=index+1;
						ts.string=sub;
						ts.width=(int)textPaint.measureText(sub);
						ts=new TabSpan(index);
						tabs.add(ts);
						break;
					}else if(ch=='\t'){
						ts.tab++;
					}else{
						TabSpan next=new TabSpan(index);
						String sub=sb.substring(ts.start,indexSaved);
						ts.end=index;
						ts.string=sub;
						ts.width=(int)textPaint.measureText(sub);
						ts.next=next;
						ts=next;
						index--;
						break;
					}
				}
			}else if(ch=='/'){//outmost
				if(++index<len){
					ch=sb.charAt(index);
					if(ch=='/'){
						TabSpan next=new TabSpan(index-1);
						String sub=sb.substring(ts.start,index-1);
						ts.end=index-1;
						ts.string=sub;
						ts.width=(int)textPaint.measureText(sub);
						ts.next=next;
						ts=next;
						ts.textColor=commentColor;
						for(index++;index<len;index++){
							ch=sb.charAt(index);
							if(ch=='\t'){
								ts.tab++;
								int indexSaved=index;
								for(index++;index<len;index++){
									ch=sb.charAt(index);
									if(ch=='\t'){
										ts.tab++;
									}else{
										sub=sb.substring(ts.start,indexSaved);
										next=new TabSpan(index);
										ts.next=next;
										ts.string=sub;
										ts.end=index;
										ts.width=(int)textPaint.measureText(sub);
										ts=next;
										index--;
										break;
									}
								}
							}else if(ch=='\n'){
								sub=sb.substring(ts.start,index);
								ts.end=index;
								ts.string=sub;
								ts.width=(int)textPaint.measureText(sub);
								ts=new TabSpan(index);
								tabs.add(ts);
								break;
							}
						}
					}else if(ts.textColor!=operator){
						TabSpan next=new TabSpan(index-1);
						String sub=sb.substring(ts.start,index-1);
						next.textColor=operator;
						ts.end=index-1;
						ts.next=next;
						ts.string=sub;
						ts.width=(int)textPaint.measureText(sub);
						ts=next;
						index--;
					}
				}else if(ts.textColor!=operator){
					String sub=sb.substring(ts.start,index-1);
					TabSpan next=new TabSpan(index-1);
					ts.next=next;
					ts.end=index;
					ts.string=sub;
					ts.width=(int)textPaint.measureText(sub);
					ts=next;
					tabs.add(ts);
				}
			}else if(Arrays.binarySearch(operators,ch)>=0){//outmost
				if(ts.textColor!=operator){
					TabSpan next=new TabSpan(index);
					String sub=sb.substring(ts.start,index);
					next.textColor=operator;
					ts.end=index;
					ts.next=next;
					ts.string=sub;
					ts.width=(int)textPaint.measureText(sub);
					ts=next;
				}
			}else if(ch=='"'){//outmost
				if(ts.textColor!=stringColor){
					TabSpan next=new TabSpan(index);
					String sub=sb.substring(ts.start,index);
					next.textColor=stringColor;
					ts.end=index;
					ts.next=next;
					ts.string=sub;
					ts.width=(int)textPaint.measureText(sub);
					ts=next;
				}
				second:
				for(index++;index<len;index++){
					ch=sb.charAt(index);
					if(ch=='\t'){
						ts.tab++;
						int indexSaved=index;
						for(index++;index<len;index++){
							ch=sb.charAt(index);
							if(ch=='\t'){
								ts.tab++;
							}else if(ch=='\n'){
								String sub=sb.substring(ts.start,indexSaved);
								TabSpan next=new TabSpan(index);
								next.textColor=stringColor;
								ts.next=next;
								ts.string=sub;
								ts.width=(int)textPaint.measureText(sub);
								ts.end=index;
								ts=next;
								break second;
							}else{
								String sub=sb.substring(ts.start,indexSaved);
								TabSpan next=new TabSpan(index);
								next.textColor=stringColor;
								ts.next=next;
								ts.string=sub;
								ts.width=(int)textPaint.measureText(sub);
								ts.end=index;
								ts=next;
								if(ch=='"'){
									index--;
								}
								break;
							}
						}
					}else if(ch=='"'){
						break;
					}else if(ch=='\n'){
						String sub=sb.substring(ts.start,index);
						TabSpan next=new TabSpan(index);
						next.textColor=stringColor;
						ts.next=next;
						ts.string=sub;
						ts.width=(int)textPaint.measureText(sub);
						ts.end=index;
						ts=next;
						break;
					}
				}
			}else if(Character.isLetter(ch)){
				int indexSaved=index;
				for(index++;index<len;index++){
					ch=sb.charAt(index);
					if(!Character.isLetter(ch)){
						String word=sb.substring(indexSaved,index);
						if(words_hashSet.contains(word)){
							if(ts.textColor!=keywordColor){
								TabSpan next=new TabSpan(indexSaved);
								String sub=sb.substring(ts.start,indexSaved);
								next.textColor=keywordColor;
								ts.next=next;
								ts.string=sub;
								ts.end=indexSaved;
								ts.width=(int)textPaint.measureText(sub);
								ts=next;
							}
						}else if(ts.textColor!=textColor){
							TabSpan next=new TabSpan(indexSaved);
							String sub=sb.substring(ts.start,indexSaved);
							next.textColor=textColor;
							ts.next=next;
							ts.end=indexSaved;
							ts.string=sub;
							ts.width=(int)textPaint.measureText(sub);
							ts=next;
						}
						index--;
						break;
					}
				}
			}else{//outmost
				if(ts.textColor!=textColor){
					TabSpan next=new TabSpan(index);
					String sub=sb.substring(ts.start,index);
					ts.string=sub;
					ts.width=(int)textPaint.measureText(sub);
					ts.end=index;
					ts.next=next;
					ts=next;
				}
			}
		}
		String sub=sb.substring(ts.start,len);
		ts.end=len;
		ts.string=sub;
		ts.width=(int)textPaint.measureText(sub);
		//tabs.add(ts);
	}
	HashSet<String> words_hashSet=new HashSet<String>();
	final static String[] words=new String[]{
		"if","else","struct","switch",
		"case","goto","enum",
		"break","return","continue",
		"for","while","do","auto",
		"register","typedef","extern",
		"union","const","unsigned",
		"signed","default","sizeof",
		"volatile","static","restrict",
		"int","void","short","long","char",
		"double","float","inline"
	};
	final static String[] types=new String[]{
		"int","void","short","long","char",
		"double","float"
	};
	final static String[] keyWords=new String[]{
		"if","else","struct","switch",
		"case","goto","enum","restrict",
		"break","return","continue",
		"for","while","do","auto",
		"register","typedef","extern",
		"union","const","unsigned",
		"signed","default","sizeof",
		"volatile","static","inline"
	};
	@Override
	public void letTextSize(int textSize) {
		textPaint.setTextSize(textSize);
		lineHeight=textSize;
		baseline=(int)(lineHeight*0.85);
		tablen=(int)textPaint.measureText(tabWidth);
		primex=getPaddingLeft()+lineHeight*2;
		primey=getPaddingTop();
		lineNumberStart=getPaddingLeft();
		int cursorWidth=Math.round(textPaint.getTextSize()/13);
		if(cursorWidth<=0)cursorWidth=1;
		cursor.setStrokeWidth(cursorWidth);
		if(text!=null){
			letText(text);
		}
	}

    @Override
    public void commitText(String s) {
        int a=Math.min(selectionStart,selectionEnd);
        int b=Math.max(selectionStart,selectionEnd);
        if(s==null||s.isEmpty()){
            if(a!=b){
                text.delete(a,b);
                selectionEnd=selectionStart;
                letText(text);
                atTextChanged();
            }
        }else if(a==b){
            text.insert(a,s);
            moveSelection(s.length(),s.length());
            letText(text);
            atTextChanged();
        }else{
            text.replace(a,b,s);
            selectionEnd=b-(b-a)+s.length();
            letText(text);
            atTextChanged();
        }
    }
	@Override
	public void letSelection(int a, int b) {
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
			return;
		}
		int len=text.length();
		if(a<0){
			a=0;
			if(b<0){
				b=0;
			}else if(b>len){
				b=len;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(a>len){
			a=len;
			if(b<0){
				b=0;
			}else if(b>len){
				b=len;
			}
			selectionStart=a;
			selectionEnd=b;
		}else if(b<0){
			b=0;
			selectionStart=a;
			selectionEnd=b;
		}else if(b>len){
			b=len;
			selectionStart=a;
			selectionEnd=b;
		}else{
			selectionStart=a;
			selectionEnd=b;
		}
	}
	@Override
	public void letSelection(int n) {
		if(text==null){
			selectionStart=0;
			selectionEnd=0;
		}else{
			if(n>=0&&n<=text.length()){
				selectionStart=n;
				selectionEnd=n;
			}else{
				log.alert("无效的参数","selection start:"+selectionStart+"\nselection end:"+selectionEnd);
			}
		}
	}
	@Override
	public void moveSelection(int a, int b) {
		final int selectionStartWill=selectionStart+a;
		final int selectionEndWill=selectionEnd+b;
		int length=text.length();
		if(selectionStartWill>=0){
			if(selectionStartWill<=length){
				selectionStart=selectionStartWill;
			}else{
				selectionStart=length;
			}
		}else{
			selectionStart=0;
		}
		if(selectionEndWill>=0){
			if(selectionEndWill<=length){
				selectionEnd=selectionEndWill;
			}else{
				selectionEnd=length;
			}
		}else{
			selectionEnd=0;
		}
	}
    boolean onTextChanged_ignoreChange;
    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        if(onTextChanged_ignoreChange){
            onTextChanged_ignoreChange=false;
            return;
        }
        String s=text.toString();
        if(s.length()>0){
            mic.commitText(s,1);
            atTextChanged();
            onTextChanged_ignoreChange=true;
            setText("");
        }
	}
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        int a=selectionStart;
        int b=selectionEnd;
        switch(keyCode){
            case KeyEvent.KEYCODE_DPAD_LEFT:
                if(a==b){
                    moveSelection(-1,-1);
                }else{
                    moveSelection(0,-1);
                }
                showCursor=true;
                tcv.againWait=true;
                tcv.interrupt();
                invalidate();
                break;
            case KeyEvent.KEYCODE_DPAD_RIGHT:
                if(a==b){
                    moveSelection(1,1);
                }else{
                    moveSelection(0,1);
                }
                showCursor=true;
                tcv.againWait=true;
                tcv.interrupt();
                invalidate();
                break;
            case KeyEvent.KEYCODE_DEL:
                if(selectionStart==selectionEnd){
                    if(selectionStart>0){
                        text.deleteCharAt(selectionStart-1);
                        selectionStart--;
                        selectionEnd--;
                        letText(text);
                        showCursor=true;
                        tcv.againWait=true;
                        tcv.interrupt();
                        atTextChanged();
                    }
                }
                break;
            default:
                int univalue=event.getUnicodeChar();
                if(univalue>=0&&univalue<256){
                    char ch=(char)univalue;
                    if(selectionStart==selectionEnd){
                        text.insert(selectionStart,ch);
                        selectionStart++;
                        selectionEnd++;
                        letText(text);
                        showCursor=true;
                        tcv.againWait=true;
                        tcv.interrupt();
                        atTextChanged();
                    }
                }
        }
        return true;
    }
    
	int calculClicked(int actionx,int actiony){
		int row=(actiony-primey)/lineHeight;
		int size=tabs.size();
		if(row>=size){
			return text.length();
		}else if(row>=0){
			TabSpan ts=tabs.get(row);
            int xx=primex;
			float lima=lineNumberStart;
			outmost:
			for(;;){
				String string=ts.string;
				float[] fs;
				if(ts.fs==null){//outmost
					fs=new float[string.length()];
					textPaint.getTextWidths(string,fs);
					ts.fs=fs;
				}else{//outmost
					fs=ts.fs;
				}
				for(int index=0;;index++){
					if(index<fs.length){
						float right=xx+fs[index]/2;
						if(actionx>=lima){
							if(actionx<right)
								return ts.start+index;
						}
						xx+=fs[index];
						lima=right;
					}else{
						int len=ts.end-ts.start;
                        for(;index<len;index++){
                            int xxWill=xx+tablen-(xx-primex)%tablen;
                            int limb=(xx+xxWill)/2;
                            if(actionx>=lima&&actionx<limb){
                                return ts.start+index;
                            }
                            lima=limb;
                            xx=xxWill;
                        }
						break;
					}
				}
				if(ts.next==null){//outmost
					return ts.end;
				}else{//outmost
					ts=ts.next;
				}
			}
		}
		return -1;
	}
	@Override
	protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
		super.onLayout(changed, left, top, right, bottom);
		currentbgcolor=ma.shr.getInt(s2,defaultbgcolor);
	}
    Paint lineHighlight=new Paint();
	@Override
	public void draw(Canvas canvas) {
		canvas.drawColor(currentbgcolor);
		if(text!=null){
			//try{
			if(onInertia){
				long dt=System.currentTimeMillis()-inertiaTime;
				if(fingerMovedOrientation==1){
					if(speed<0){
						float speedNow=speed+inertia*dt;
						if(speedNow<-minSpeed){
							int scrollYWill=inertiaScrollY-(int)(speed*dt+inertia*dt*dt/2);
							if(scrollYWill>=scrollYMaximum){
								scrollY=scrollYMaximum;
								onInertia=false;
							}else{
								scrollY=scrollYWill;
								invalidate();
							}
						}else{
							onInertia=false;
						}
					}else{
						float speedNow=speed-inertia*dt;
						if(speedNow>minSpeed){
							int scrollYWill=inertiaScrollY-(int)(speed*dt-inertia*dt*dt/2);
							if(scrollYWill<=0){
								scrollY=0;
								onInertia=false;
							}else{
								scrollY=scrollYWill;
								invalidate();
							}
						}else{
							onInertia=false;
						}
					}
				}else if(fingerMovedOrientation==2){
					if(speed<0){
						float speedNow=speed+inertia*dt;
						if(speedNow<-minSpeed){
							int scrollXWill=inertiaScrollX-(int)(speed*dt+inertia*dt*dt/2);
							if(scrollXWill>=scrollXMaximum){
								scrollX=scrollXMaximum;
								onInertia=false;
							}else{
								scrollX=scrollXWill;
								invalidate();
							}
						}else{
							onInertia=false;
						}
					}else if(speed>0){
						float speedNow=speed-inertia*dt;
						if(speedNow>minSpeed){
							int scrollXWill=inertiaScrollX-(int)(speed*dt-inertia*dt*dt/2);
							if(scrollXWill<=0){
								scrollX=0;
								onInertia=false;
							}else{
								scrollX=scrollXWill;
								invalidate();
							}
						}else{
							onInertia=false;
						}
					}else{
						onInertia=false;
					}
				}else{
					onInertia=false;
				}
			}
			int vw=getWidth();
			int vh=getHeight();
			int startx=primex;
			int startLine=(scrollY-primey)/lineHeight;
			int size=tabs.size();
			TabSpan ts;
			if(startLine>=size)return;
			scrollYMaximum=size*lineHeight+primey;
			scrollXMaximum=0;
			int starty=primey+startLine*lineHeight;
			int startyAbove=scrollY+vh;
			int startxAbove=scrollX+vw;
			int line=startLine+1;
			int jx=(int)((baseline-(0.75*baseline))/2+(baseline*0.8));
			int tabIndex=startLine;
			canvas.translate(-scrollX,-scrollY);
			lineNumber.setTextSize(textPaint.getTextSize()*0.75f);
            int endline=(scrollY+vh-primey)/lineHeight+1;
            drawLineBackground:
            for(int a=startLine,b=endline<size?endline:size;;){
                if(a<b){
                    int mid=a+(b-a)/2;
                    int offs=tabs.get(mid).start;
                    if(selectionStart<offs){
                        b=mid;
                        if(a==b)break;
                    }else{
                        if(mid+1<size){
                            a=mid+1;
                            offs=tabs.get(mid+1).start;
                            if(selectionStart<offs){
                                int t=mid*lineHeight+primey;
                                canvas.drawRect(scrollX,t,scrollX+vw,t+lineHeight,lineHighlight);
                                break;
                            }
                        }else{
                            int t=(mid)*lineHeight+primey;
                            canvas.drawRect(scrollX,t,scrollX+vw,t+lineHeight,lineHighlight);
                            break;
                        }
                    }
                }else{
                    break;
                }
            }
			drawText:
			for(;starty<startyAbove&&tabIndex<size;tabIndex++){
				ts=tabs.get(tabIndex);
				canvas.drawText(String.format("%03d",line),lineNumberStart,starty+jx,lineNumber);
				for(;;){
					TabSpan next=ts.next;
					String string=ts.string;
					textPaint.setColor(ts.textColor);
					canvas.drawText(string,startx,starty+baseline,textPaint);
					int startxWill=startx+ts.width;
					if(ts.tab>0)startxWill+=ts.tab*tablen-(startxWill-primex)%tablen;
					if(selectionStart>=ts.start){
						if(selectionStart<ts.end){
                            float[] fs;
                            if(ts.fs==null){
                                fs=new float[string.length()];
                                textPaint.getTextWidths(string,fs);
                                ts.fs=fs;
                            }else{
                                fs=ts.fs;
                            }
							if(selectionStart==selectionEnd){
								if(showCursor){
									float xx=startx;
                                    measure:
                                    for(int ii=0;;ii++){
                                        if(ii<fs.length){
                                            if(ts.start+ii==selectionEnd){
                                                canvas.drawLine(xx,starty,xx,starty+lineHeight,cursor);
                                                break;
                                            }
                                            xx+=fs[ii];
                                        }else{
                                            for(;;ii++){
                                                if(ts.start+ii==selectionEnd){
                                                    canvas.drawLine(xx,starty,xx,starty+lineHeight,cursor);
                                                    break;
                                                }
                                                xx+=tablen-(xx-primex)%tablen;
                                            }
                                            break;
                                        }
									}
								}
							}else if(selectionEnd<ts.end){
                                int a=Math.min(selectionStart,selectionEnd);
                                int b=Math.max(selectionStart,selectionEnd);
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii>=a){
                                            int xxSaved=xx;
                                            xx+=fs[ii];
                                            for(ii++;;ii++){
                                                if(ii<fs.length){
                                                    if(ts.start+ii==b){
                                                        canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                        break;
                                                    }
                                                    xx+=fs[ii];
                                                }else{
                                                    for(;;ii++){
                                                        if(ts.start+ii==b){
                                                            canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                            //canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
                                                            break;
                                                        }
                                                        xx+=tablen-(xx-primex)%tablen;
                                                    }
                                                    break;
                                                }
                                            }
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii>=a){
                                                int xxSaved=xx;
                                                for(ii++;;ii++){
                                                    if(ts.start+ii==b){
                                                        canvas.drawRect(xxSaved,starty,xx,starty+lineHeight,selectionbgcolor);
                                                        break;
                                                    }
                                                }
                                                //canvas.drawRect(x,y,xx,y+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }else if(next==null){
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionStart){
                                            canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionStart){
                                                canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }else{
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionStart){
                                            canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionStart){
                                                canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }
						}else if(selectionEnd>=ts.start){
                            float[] fs;
                            if(ts.fs==null){
                                fs=new float[string.length()];
                                textPaint.getTextWidths(string,fs);
                                ts.fs=fs;
                            }else{
                                fs=ts.fs;
                            }
                            if(selectionEnd<ts.end){
                                int xx=startx;
                                measure:
                                for(int ii=0;;ii++){
                                    if(ii<fs.length){
                                        if(ts.start+ii==selectionEnd){
                                            if(next==null){
                                                canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                            }else{
                                                canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                            }
                                            break;
                                        }
                                        xx+=fs[ii];
                                    }else{
                                        for(;;ii++){
                                            if(ts.start+ii==selectionEnd){
                                                if(next==null){
                                                    canvas.drawRect(xx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                                                }else{
                                                    canvas.drawRect(xx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                                                }
                                                break;
                                            }
                                            xx+=tablen-(xx-primex)%tablen;
                                        }
                                        break;
                                    }
                                }
                            }else if(next==null){
                                if(selectionStart==ts.end){
                                    if(selectionEnd==ts.end){
                                        canvas.drawLine(startxWill,starty,startxWill,starty+lineHeight,cursor);
                                    }else{
                                        canvas.drawRect(startx,starty,scrollX+vw,starty+lineHeight,lineHighlight);
                                    }
                                }else if(selectionEnd==ts.end){
                                    canvas.drawRect(startx,starty,scrollX+vw,starty+lineHeight,lineHighlight);
                                }
                            }
                        }else if(next==null){
                            canvas.drawRect(startx,starty,vw+scrollX,starty+lineHeight,selectionbgcolor);
                        }else{
                            canvas.drawRect(startx,starty,startxWill,starty+lineHeight,selectionbgcolor);
                        }/*else if(ts.next==null&&tabsIndex+1>size){
						 textPaint.setColor(currentLineHighlight);
						 canvas.drawRect(scrollX,starty,vw+scrollX,starty+lineHeight,textPaint);
						 canvas.drawLine(startx+ts.width,starty,startx+ts.width,starty+lineHeight,cursor);
						 }*/
					}else if(selectionEnd>=ts.start){
						if(selectionEnd<ts.end){
							if(selectionEnd>selectionStart){
								float[] fs;
								if(ts.fs==null){
									fs=new float[string.length()];
									textPaint.getTextWidths(string,fs);
									ts.fs=fs;
								}else{
									fs=ts.fs;
								}
								float xx=startx;
								int index=ts.start;
								for(;true;index++){
									if(index==selectionEnd){
										xx+=fs[index-ts.start];
										canvas.drawRect(startx,starty,xx,starty+lineHeight,selection);
										break;
									}else if(index<ts.start+fs.length){
										xx+=fs[index-ts.start];
									}else{
										int mod=((int)xx-primex)%tablen;
										index++;
										for(int tt=1;tt<ts.tab;tt++,index++){
											if(index==selectionEnd){
												xx=tablen*(tt+1)-mod;
												canvas.drawRect(startx,starty,xx,starty+lineHeight,selection);
												break;
											}
										}
									}
								}
							}else if(selectionEnd<selectionStart){
								float[] fs;
								if(ts.fs==null){
									fs=new float[string.length()];
									textPaint.getTextWidths(string,fs);
									ts.fs=fs;
								}else{
									fs=ts.fs;
								}
								float xx=startx;
								int index=ts.start;
								for(;true;index++){
									if(index==selectionEnd){
										canvas.drawRect(xx,starty,startx+ts.width,starty+lineHeight,selection);
										break;
									}else if(index<ts.start+fs.length){
										xx+=fs[index-ts.start];
									}else{
										int mod=((int)xx-primex)%tablen;
										index++;
										for(int tt=1;tt<ts.tab;tt++,index++){
											if(index==selectionEnd){
												xx=tablen*(tt)-mod;
												canvas.drawRect(xx,starty,startx+ts.width,starty+lineHeight,selection);
												break;
											}
										}
									}
								}
							}
						}
					}
					startx=startxWill;
					if(next==null){
						break;
					}else if(startx<startxAbove){
						ts=next;
					}else{
						break;
					}
				}
				if(startx>scrollXMaximum)scrollXMaximum=startx;
				starty+=lineHeight;
				startx=primex;
				line++;
			}
            /*int len=text.length();
            if(tabIndex==size){
                if(selectionStart==len){
                    if(selectionStart==selectionEnd){
                        canvas.drawLine(startx,starty-lineHeight,startx,starty,cursor);
                    }
                }
			}*/
			/*}catch(Exception e){
				log.alert("void draw",e.toString());/////////////
			}*/
		}else{
			int textColorSaved=textPaint.getColor();
			textPaint.setColor(0xff777777);
			canvas.drawText("Null",getPaddingLeft(),getPaddingTop()+lineHeight,textPaint);
			textPaint.setColor(textColorSaved);
		}
	}
	int touchDownX;
	int touchDownY;
	int touchSavedX;
	int touchSavedY;
	int touchOldX;
	int touchOldY;
	int scrollXSaved;
	int scrollYSaved;
	int fingerMovedOrientation;
	int inertiaScrollX;
	int inertiaScrollY;
	int textSizeSaved;
	double distanceSaved;
	float minSpeed=0.001f;
	float inertia;
	float speed;
	long touchTimeOld;
	long inertiaTime;
	boolean scaleing;
	boolean fingerPressed;
	boolean onInertia;
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		int ex=(int)event.getX();
		int ey=(int)event.getY();
		switch(event.getActionMasked()){
			case MotionEvent.ACTION_DOWN:
				touchDownX=ex;
				touchDownY=ey;
				touchSavedX=ex;
				touchSavedY=ey;
				touchOldX=ex;
				touchOldY=ey;
				touchTimeOld=System.currentTimeMillis();
				scrollXSaved=scrollX;
				scrollYSaved=scrollY;
				scaleing=false;
				fingerPressed=true;
				fingerMovedOrientation=0;
				onInertia=false;
				textSizeSaved=(int)textPaint.getTextSize();
				break;
			case MotionEvent.ACTION_POINTER_DOWN:
				if(!scaleing){
					scaleing=true;
					float a=Math.abs(ex-event.getX(1));
					float b=Math.abs(ey-event.getY(1));
					distanceSaved=Math.sqrt(a*a+b*b);
				}
				break;
			case MotionEvent.ACTION_MOVE:
				if(event.getPointerCount()==1){
					if(!scaleing){
						if(fingerMovedOrientation==0){
							int dx=Math.abs(ex-touchDownX);
							int dy=Math.abs(ey-touchDownY);
							if(dx>fingerMovedLim||dy>fingerMovedLim){
								if(dx>dy){
									fingerMovedOrientation=2;
									long dt=System.currentTimeMillis()-touchTimeOld;
									if(dt>0){
										speed=(ex-touchOldX)/dt;
									}
								}else{
									fingerMovedOrientation=1;
									long dt=System.currentTimeMillis()-touchTimeOld;
									if(dt>0){
										speed=(ey-touchOldY)/dt;
									}
								}
							}
						}else if(fingerMovedOrientation==1){
							int dy=ey-touchSavedY;
							int scrollYWill=scrollYSaved-dy;
							if(scrollYWill<=0){
								scrollYSaved=0;
								touchSavedY=ey;
								scrollY=0;
								invalidate();
							}else if(scrollYWill>=scrollYMaximum){
								scrollYSaved=scrollYMaximum;
								touchSavedY=ey;
								scrollY=scrollYMaximum;
								invalidate();
							}else{
								scrollY=scrollYWill;
								invalidate();
							}
							long dt=System.currentTimeMillis()-touchTimeOld;
							if(dt>0){
								float speedWill=(ey-touchOldY)/dt;
								speed=(speedWill+speed)/2;
							}
						}else if(fingerMovedOrientation==2){
							int dx=ex-touchSavedX;
							int scrollXWill=scrollXSaved-dx;
							if(scrollXWill<=0){
								scrollXSaved=0;
								touchSavedX=ex;
								scrollX=0;
								invalidate();
							}else if(scrollXWill>=scrollXMaximum){
								scrollXSaved=scrollXMaximum;
								touchSavedX=ex;
								scrollX=scrollXMaximum;
								invalidate();
							}else{
								scrollX=scrollXWill;
								invalidate();
							}
							long dt=System.currentTimeMillis()-touchTimeOld;
							if(dt>0){
								float speedWill=(ex-touchOldX)/dt;
								speed=(speedWill+speed)/2;
							}
						}
					}
				}else{
					scaleing=true;
					float a=Math.abs(ex-event.getX(1));
					float b=Math.abs(ey-event.getY(1));
					double dis=Math.sqrt(a*a+b*b);
					double rate=dis/distanceSaved;
					int sizeWill=(int)(textSizeSaved*rate);
					if(sizeWill<=maxTextSize){
						if(sizeWill>=minTextSize){
							letTextSize(sizeWill);
						}else{
							letTextSize(minTextSize);
						}
					}else{
						letTextSize(maxTextSize);
					}
					invalidate();
				}
				touchTimeOld=System.currentTimeMillis();
				touchOldX=ex;
				touchOldY=ey;
				break;
			case MotionEvent.ACTION_UP:
				fingerPressed=false;
				if(!scaleing){
					if(fingerMovedOrientation==0){
						int clicked=calculClicked(ex+scrollX,ey+scrollY);
						if(clicked>=0){
							selectionStart=clicked;
							selectionEnd=clicked;
                            showCursor=true;
                            tcv.againWait=true;
                            tcv.interrupt();
							if(canShowSoftInput){
                                if(requestFocus()){
                                    ma.imm.showSoftInput(this,0);
                                }
                            }
                            invalidate();
                            /*if(clicked==text.length()){
                                cep.status.setText("clicked the last char");
                            }else
							cep.status.setText("clicked:"+clicked+",char:"+text.charAt(clicked));*/
						}
					}else{
						onInertia=true;
						inertiaTime=System.currentTimeMillis();
						inertiaScrollX=scrollX;
						inertiaScrollY=scrollY;
						invalidate();
					}
				}
				break;
			case MotionEvent.ACTION_CANCEL:
				fingerPressed=false;
		}
		return true;
	}
	@Override
	public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
		InputConnection former=super.onCreateInputConnection(outAttrs);
		mic=new MyInputConnection(former);
		return mic;
	}
	class MyInputConnection extends InputConnectionWrapper{
		InputConnection former;
		MyInputConnection(InputConnection former){
			super(former,false);
			this.former=former;
		}

        @Override
        public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
            return false;
        }
        @Override
        public boolean sendKeyEvent(KeyEvent event) {
            return former.sendKeyEvent(event);
        }
        @Override
        public boolean deleteSurroundingText(int beforeLength, int afterLength) {
            if(!canEdit)return false;
            if(beforeLength<0||afterLength<0)return false;
            int a=selectionStart;
            int b=selectionEnd;
            if(a<b){
                int start=a-beforeLength;
                int end=b;
                if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
                letSelection(start);
                end=a+afterLength;
                atTextChanged();
                if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
                letText(text);
            }else if(a==b){
                int start=a-beforeLength;
                int end=a;
                if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
                letSelection(start);
                end=start+afterLength;
                atTextChanged();
                if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
                letText(text);
            }else{
                int start=b-beforeLength;
                int end=a;
                if(start<0){
                    text.delete(0,end);
                }else{
                    text.delete(start,end);
                }
                letSelection(start);
                end=start+afterLength;
                atTextChanged();
                if(end>text.length()){
                    text.delete(start,text.length());
                }else{
                    text.delete(start,end);
                }
                letText(text);
            }
            tcv.againWait=true;
            showCursor=true;
            tcv.interrupt();
            invalidate();
            return true;
		}
        @Override
        public boolean commitText(CharSequence commit, int newCursorPosition) {
            int selectionA=Math.min(selectionStart,selectionEnd);
            //int selectionB=Math.max(selectionStart,selectionEnd);//text will replace with a and b
            String baseindent="";
            for(int index=selectionA-1;index>=0;index--){
                if(index>=0){
                    char ch=text.charAt(index);
                    if(ch=='\n'){
                        for(index++;index<text.length();index++){
                            ch=text.charAt(index);
                            if(ch=='\t'){
                                baseindent+='\t';
                            }else break;
                        }
                        break;
                    }
                }
            }
            StringBuilder commit_sb=new StringBuilder();
            outmost:
            for(int index=0,len=commit.length();index<len;index++){
                char ch=commit.charAt(index);
                if(ch=='\n'){
                    commit_sb.append(ch);
                    commit_sb.append(baseindent);
                    for(index++;index<len;index++){
                        ch=commit.charAt(index);
                        if(ch!='\t'){
                            index--;
                            break;
                        }
                    }
                }else{
                    commit_sb.append(ch);
                }
            }
            text.replace(selectionStart,selectionEnd,commit_sb.toString());
            letText(text);
            atTextChanged();
            if(selectionStart<selectionEnd){
                selectionEnd=selectionStart+commit_sb.length();
                selectionStart=selectionEnd;
            }else if(selectionStart==selectionEnd){
                selectionEnd=selectionStart+commit_sb.length();
                selectionStart=selectionEnd;
            }else{
                selectionStart=selectionEnd+commit_sb.length();
                selectionEnd=selectionStart;
            }
            return true;
		}
	}
	class AutoHideHandle extends Thread{
		@Override
		public void run(){
			try{
				sleep(800);
				handleOnShow=false;
				CIndentEditor.this.postInvalidate();
			}catch(InterruptedException e){
			}catch(Exception e){
				log.alert(e.toString());
			}
			super.run();
		}
	}
}
